35ac8b
@@ -27,751 +27,225 @@
 import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 
 /**
  * A {@link org.apache.hadoop.hive.metastore.api.StorageDescriptor} with most of it's content
- * shared.  Location and parameters are left alone, everything else is redirected to a shared
- * reference in the cache.
+ * shallow copied from the underlying storage descriptor.  Location and parameters are left alone.
+ * To avoid issues when users change the contents, all lists and nested structures (cols, serde,
+ * buckets, sortCols, and skewed) are deep copied when they are accessed for reading or writing.
+ * (It has to be done on read as well because there's no way to guarantee the user won't change the
+ * nested structure or list, which would result in changing every storage descriptor sharing that
+ * structure.)  Users wishing better performance can call setReadyOnly(), which will prevent the
+ * copies.
  */
 public class SharedStorageDescriptor extends StorageDescriptor {
   static final private Log LOG = LogFactory.getLog(SharedStorageDescriptor.class.getName());
-  private StorageDescriptor shared;
-  private boolean copied = false;
-  private CopyOnWriteColList colList = null;
-  private CopyOnWriteOrderList orderList = null;
-  private CopyOnWriteBucketList bucketList = null;
+  private boolean colsCopied = false;
+  private boolean serdeCopied = false;
+  private boolean bucketsCopied = false;
+  private boolean sortCopied = false;
+  private boolean skewedCopied = false;
 
   SharedStorageDescriptor() {
   }
 
-  public SharedStorageDescriptor(SharedStorageDescriptor that) {
-    this.setLocation(that.getLocation());
-    this.setParameters(that.getParameters());
-    this.shared = that.shared;
+  void setShared(StorageDescriptor shared) {
+    if (shared.getCols() != null) super.setCols(shared.getCols());
+    // Skip location
+    if (shared.getInputFormat() != null) super.setInputFormat(shared.getInputFormat());
+    if (shared.getOutputFormat() != null) super.setOutputFormat(shared.getOutputFormat());
+    super.setCompressed(shared.isCompressed());
+    super.setNumBuckets(shared.getNumBuckets());
+    if (shared.getSerdeInfo() != null) super.setSerdeInfo(shared.getSerdeInfo());
+    if (shared.getBucketCols() != null) super.setBucketCols(shared.getBucketCols());
+    if (shared.getSortCols() != null) super.setSortCols(shared.getSortCols());
+    // skip parameters
+    if (shared.getSkewedInfo() != null) super.setSkewedInfo(shared.getSkewedInfo());
+    super.setStoredAsSubDirectories(shared.isStoredAsSubDirectories());
   }
 
-  @Override
-  public StorageDescriptor deepCopy() {
-    return new SharedStorageDescriptor(this);
+  /**
+   * Promise that you'll only use this shared storage descriptor in a read only mode.
+   * This prevents the copies of the nested structures and lists when reading them.  However, the
+   * caller must not change the structures or lists returned to it, as this will change all
+   * storage descriptor sharing that list.
+   */
+  public void setReadOnly() {
+    colsCopied = serdeCopied = bucketsCopied = sortCopied = skewedCopied = true;
   }
 
   @Override
-  public boolean isSetCols() {
-    return shared.isSetCols();
+  public void addToCols(FieldSchema fs) {
+    copyCols();
+    super.addToCols(fs);
   }
 
   @Override
   public List<FieldSchema> getCols() {
-    return copied ? shared.getCols() : (
-        shared.getCols() == null ? null : copyCols(shared.getCols()));
-  }
-
-  @Override
-  public int getColsSize() {
-    return shared.getColsSize();
-  }
-
-  @Override
-  public Iterator<FieldSchema> getColsIterator() {
-    return shared.getColsIterator();
+    copyCols();
+    return super.getCols();
   }
 
   @Override
   public void setCols(List<FieldSchema> cols) {
-    copyOnWrite();
-    shared.setCols(cols);
-  }
-
-  @Override
-  public void addToCols(FieldSchema fs) {
-    copyOnWrite();
-    shared.addToCols(fs);
+    colsCopied = true;
+    super.setCols(cols);
   }
 
   @Override
   public void unsetCols() {
-    copyOnWrite();
-    shared.unsetCols();
+    colsCopied = true;
+    super.unsetCols();
   }
 
   @Override
-  public boolean isSetInputFormat() {
-    return shared.isSetInputFormat();
-  }
-
-  @Override
-  public String getInputFormat() {
-    return shared.getInputFormat();
-  }
-
-  @Override
-  public void setInputFormat(String inputFormat) {
-    copyOnWrite();
-    shared.setInputFormat(inputFormat);
-  }
-
-  @Override
-  public void unsetInputFormat() {
-    copyOnWrite();
-    shared.unsetInputFormat();
-  }
-
-  @Override
-  public boolean isSetOutputFormat() {
-    return shared.isSetOutputFormat();
-  }
-
-  @Override
-  public String getOutputFormat() {
-    return shared.getOutputFormat();
-  }
-
-  @Override
-  public void setOutputFormat(String outputFormat) {
-    copyOnWrite();
-    shared.setOutputFormat(outputFormat);
-  }
-
-  @Override
-  public void unsetOutputFormat() {
-    copyOnWrite();
-    shared.unsetOutputFormat();
-  }
-
-  @Override
-  public boolean isSetCompressed() {
-    return shared.isSetCompressed();
-  }
-
-  @Override
-  public boolean isCompressed() {
-    return shared.isCompressed();
-  }
-
-  @Override
-  public void setCompressed(boolean isCompressed) {
-    copyOnWrite();
-    shared.setCompressed(isCompressed);
-  }
-
-  @Override
-  public void unsetCompressed() {
-    copyOnWrite();
-    shared.unsetCompressed();
-  }
-
-  @Override
-  public boolean isSetNumBuckets() {
-    return shared.isSetNumBuckets();
-  }
-
-  @Override
-  public int getNumBuckets() {
-    return shared.getNumBuckets();
-  }
-
-  @Override
-  public void setNumBuckets(int numBuckets) {
-    copyOnWrite();
-    shared.setNumBuckets(numBuckets);
-  }
-
-  @Override
-  public void unsetNumBuckets() {
-    copyOnWrite();
-    shared.unsetNumBuckets();
+  public Iterator<FieldSchema> getColsIterator() {
+    copyCols();
+    return super.getColsIterator();
   }
 
-  @Override
-  public boolean isSetSerdeInfo() {
-    return shared.isSetSerdeInfo();
+  private void copyCols() {
+    if (!colsCopied) {
+      colsCopied = true;
+      if (super.getCols() != null) {
+        List<FieldSchema> cols = new ArrayList<FieldSchema>(super.getColsSize());
+        for (FieldSchema fs : super.getCols()) cols.add(new FieldSchema(fs));
+        super.setCols(cols);
+      }
+    }
   }
 
   @Override
   public SerDeInfo getSerdeInfo() {
-    return copied ? shared.getSerdeInfo() : (
-        shared.getSerdeInfo() == null ? null : new SerDeInfoWrapper(shared.getSerdeInfo()));
+    copySerde();
+    return super.getSerdeInfo();
   }
 
   @Override
   public void setSerdeInfo(SerDeInfo serdeInfo) {
-    copyOnWrite();
-    shared.setSerdeInfo(serdeInfo);
+    serdeCopied = true;
+    super.setSerdeInfo(serdeInfo);
   }
 
   @Override
   public void unsetSerdeInfo() {
-    copyOnWrite();
-    shared.unsetSerdeInfo();
-  }
-
-  @Override
-  public boolean isSetBucketCols() {
-    return shared.isSetBucketCols();
+    serdeCopied = true;
+    super.unsetSerdeInfo();
   }
 
-  @Override
-  public List<String> getBucketCols() {
-    return copied ? shared.getBucketCols() : (
-        shared.getBucketCols() == null ? null : copyBucketCols(shared.getBucketCols()));
-  }
-
-  @Override
-  public int getBucketColsSize() {
-    return shared.getBucketColsSize();
+  private void copySerde() {
+    if (!serdeCopied) {
+      serdeCopied = true;
+      if (super.getSerdeInfo() != null) super.setSerdeInfo(new SerDeInfo(super.getSerdeInfo()));
+    }
   }
 
   @Override
-  public Iterator<String> getBucketColsIterator() {
-    return shared.getBucketColsIterator();
+  public void addToBucketCols(String bucket) {
+    copyBucketCols();
+    super.addToBucketCols(bucket);
   }
 
   @Override
-  public void setBucketCols(List<String> bucketCols) {
-    copyOnWrite();
-    shared.setBucketCols(bucketCols);
+  public List<String> getBucketCols() {
+    copyBucketCols();
+    return super.getBucketCols();
   }
 
   @Override
-  public void addToBucketCols(String bucketCol) {
-    copyOnWrite();
-    shared.addToBucketCols(bucketCol);
+  public void setBucketCols(List<String> buckets) {
+    bucketsCopied = true;
+    super.setBucketCols(buckets);
   }
 
   @Override
   public void unsetBucketCols() {
-    copyOnWrite();
-    shared.unsetBucketCols();
+    bucketsCopied = true;
+    super.unsetBucketCols();
   }
 
   @Override
-  public boolean isSetSortCols() {
-    return shared.isSetSortCols();
+  public Iterator<String> getBucketColsIterator() {
+    copyBucketCols();
+    return super.getBucketColsIterator();
   }
 
-  @Override
-  public List<Order> getSortCols() {
-    return copied ? shared.getSortCols() : (
-        shared.getSortCols() == null ? null : copySort(shared.getSortCols()));
+  private void copyBucketCols() {
+    if (!bucketsCopied) {
+      bucketsCopied = true;
+      if (super.getBucketCols() != null) {
+        List<String> buckets = new ArrayList<String>(super.getBucketColsSize());
+        for (String bucket : super.getBucketCols()) buckets.add(bucket);
+        super.setBucketCols(buckets);
+      }
+    }
   }
 
   @Override
-  public int getSortColsSize() {
-    return shared.getSortColsSize();
+  public void addToSortCols(Order sort) {
+    copySort();
+    super.addToSortCols(sort);
   }
 
   @Override
-  public Iterator<Order> getSortColsIterator() {
-    return shared.getSortColsIterator();
+  public List<Order> getSortCols() {
+    copySort();
+    return super.getSortCols();
   }
 
   @Override
-  public void setSortCols(List<Order> sortCols) {
-    copyOnWrite();
-    shared.setSortCols(sortCols);
+  public void setSortCols(List<Order> sorts) {
+    sortCopied = true;
+    super.setSortCols(sorts);
   }
 
   @Override
-  public void addToSortCols(Order sortCol) {
-    copyOnWrite();
-    shared.addToSortCols(sortCol);
+  public void unsetSortCols() {
+    sortCopied = true;
+    super.unsetSortCols();
   }
 
   @Override
-  public void unsetSortCols() {
-    copyOnWrite();
-    shared.unsetSortCols();
+  public Iterator<Order> getSortColsIterator() {
+    copySort();
+    return super.getSortColsIterator();
   }
 
-  @Override
-  public boolean isSetSkewedInfo() {
-    return shared.isSetSkewedInfo();
+  private void copySort() {
+    if (!sortCopied) {
+      sortCopied = true;
+      if (super.getSortCols() != null) {
+        List<Order> sortCols = new ArrayList<Order>(super.getSortColsSize());
+        for (Order sortCol : super.getSortCols()) sortCols.add(new Order(sortCol));
+        super.setSortCols(sortCols);
+      }
+    }
   }
 
   @Override
   public SkewedInfo getSkewedInfo() {
-    return copied ? shared.getSkewedInfo() : (
-        shared.getSkewedInfo() == null ? null : new SkewWrapper(shared.getSkewedInfo()));
+    copySkewed();
+    return super.getSkewedInfo();
   }
 
   @Override
   public void setSkewedInfo(SkewedInfo skewedInfo) {
-    copyOnWrite();
-    shared.setSkewedInfo(skewedInfo);
+    skewedCopied = true;
+    super.setSkewedInfo(skewedInfo);
   }
 
   @Override
   public void unsetSkewedInfo() {
-    copyOnWrite();
-    shared.unsetSkewedInfo();
-  }
-
-  @Override
-  public boolean isSetStoredAsSubDirectories() {
-    return shared.isSetStoredAsSubDirectories();
-  }
-
-  @Override
-  public boolean isStoredAsSubDirectories() {
-    return shared.isStoredAsSubDirectories();
-  }
-
-  @Override
-  public void setStoredAsSubDirectories(boolean sasd) {
-    copyOnWrite();
-    shared.setStoredAsSubDirectories(sasd);
-  }
-
-  @Override
-  public void unsetStoredAsSubDirectories() {
-    copyOnWrite();
-    shared.unsetStoredAsSubDirectories();
+    skewedCopied = true;
+    super.unsetSkewedInfo();
   }
 
-  void setShared(StorageDescriptor sd) {
-    shared = sd;
-  }
-
-  StorageDescriptor getShared() {
-    return shared;
-  }
-
-  private void copyOnWrite() {
-    if (!copied) {
-      shared = new StorageDescriptor(shared);
-      copied = true;
-    }
-  }
-
-  private class SerDeInfoWrapper extends SerDeInfo {
-
-    SerDeInfoWrapper(SerDeInfo serde) {
-      super(serde);
-    }
-
-    @Override
-    public void setName(String name) {
-      copyOnWrite();
-      shared.getSerdeInfo().setName(name);
-    }
-
-    @Override
-    public void unsetName() {
-      copyOnWrite();
-      shared.getSerdeInfo().unsetName();
-    }
-
-    @Override
-    public void setSerializationLib(String lib) {
-      copyOnWrite();
-      shared.getSerdeInfo().setSerializationLib(lib);
-    }
-
-    @Override
-    public void unsetSerializationLib() {
-      copyOnWrite();
-      shared.getSerdeInfo().unsetSerializationLib();
-    }
-
-    @Override
-    public void setParameters(Map<String, String> parameters) {
-      copyOnWrite();
-      shared.getSerdeInfo().setParameters(parameters);
-    }
-
-    @Override
-    public void unsetParameters() {
-      copyOnWrite();
-      shared.getSerdeInfo().unsetParameters();
-    }
-
-    @Override
-    public void putToParameters(String key, String value) {
-      copyOnWrite();
-      shared.getSerdeInfo().putToParameters(key, value);
+  private void copySkewed() {
+    if (!skewedCopied) {
+      skewedCopied = true;
+      if (super.getSkewedInfo() != null) super.setSkewedInfo(new SkewedInfo(super.getSkewedInfo()));
     }
   }
-
-  private class SkewWrapper extends SkewedInfo {
-    SkewWrapper(SkewedInfo skew) {
-      super(skew);
-    }
-
-    @Override
-    public void setSkewedColNames(List<String> skewedColNames) {
-      copyOnWrite();
-      shared.getSkewedInfo().setSkewedColNames(skewedColNames);
-    }
-
-    @Override
-    public void unsetSkewedColNames() {
-      copyOnWrite();
-      shared.getSkewedInfo().unsetSkewedColNames();
-    }
-
-    @Override
-    public void addToSkewedColNames(String skewCol) {
-      copyOnWrite();
-      shared.getSkewedInfo().addToSkewedColNames(skewCol);
-    }
-
-    @Override
-    public void setSkewedColValues(List<List<String>> skewedColValues) {
-      copyOnWrite();
-      shared.getSkewedInfo().setSkewedColValues(skewedColValues);
-    }
-
-    @Override
-    public void unsetSkewedColValues() {
-      copyOnWrite();
-      shared.getSkewedInfo().unsetSkewedColValues();
-    }
-
-    @Override
-    public void addToSkewedColValues(List<String> skewedColValue) {
-      copyOnWrite();
-      shared.getSkewedInfo().addToSkewedColValues(skewedColValue);
-    }
-
-    @Override
-    public void setSkewedColValueLocationMaps(Map<List<String>, String> maps) {
-      copyOnWrite();
-      shared.getSkewedInfo().setSkewedColValueLocationMaps(maps);
-    }
-
-    @Override
-    public void unsetSkewedColValueLocationMaps() {
-      copyOnWrite();
-      shared.getSkewedInfo().unsetSkewedColValueLocationMaps();
-    }
-
-    @Override
-    public void putToSkewedColValueLocationMaps(List<String> key, String value) {
-      copyOnWrite();
-      shared.getSkewedInfo().putToSkewedColValueLocationMaps(key, value);
-    }
-  }
-
-  private CopyOnWriteOrderList copySort(List<Order> sort) {
-    if (orderList == null) {
-      orderList = new CopyOnWriteOrderList(sort.size());
-      for (int i = 0; i < sort.size(); i++) {
-        orderList.secretAdd(new OrderWrapper(i, sort.get(i)));
-      }
-    }
-    return orderList;
-  }
-
-  private class CopyOnWriteOrderList extends ArrayList<Order> {
-
-    CopyOnWriteOrderList(int size) {
-      super(size);
-    }
-
-    private void secretAdd(OrderWrapper order) {
-      super.add(order);
-    }
-
-    @Override
-    public boolean add(Order t) {
-      copyOnWrite();
-      return shared.getSortCols().add(t);
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      copyOnWrite();
-      return shared.getSortCols().remove(o);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends Order> c) {
-      copyOnWrite();
-      return shared.getSortCols().addAll(c);
-    }
-
-    @Override
-    public boolean addAll(int index, Collection<? extends Order> c) {
-      copyOnWrite();
-      return shared.getSortCols().addAll(c);
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      copyOnWrite();
-      return shared.getSortCols().removeAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      copyOnWrite();
-      return shared.getSortCols().retainAll(c);
-    }
-
-    @Override
-    public void clear() {
-      copyOnWrite();
-      shared.getSortCols().clear();
-    }
-
-    @Override
-    public Order set(int index, Order element) {
-      copyOnWrite();
-      return shared.getSortCols().set(index, element);
-    }
-
-    @Override
-    public void add(int index, Order element) {
-      copyOnWrite();
-      shared.getSortCols().add(index, element);
-    }
-
-    @Override
-    public Order remove(int index) {
-      copyOnWrite();
-      return shared.getSortCols().remove(index);
-    }
-  }
-
-  private class OrderWrapper extends Order {
-    final private int pos;
-
-    OrderWrapper(int pos, Order order) {
-      super(order);
-      this.pos = pos;
-    }
-
-    @Override
-    public void setCol(String col) {
-      copyOnWrite();
-      shared.getSortCols().get(pos).setCol(col);
-    }
-
-    @Override
-    public void unsetCol() {
-      copyOnWrite();
-      shared.getSortCols().get(pos).unsetCol();
-    }
-
-    @Override
-    public void setOrder(int order) {
-      copyOnWrite();
-      shared.getSortCols().get(pos).setOrder(order);
-    }
-
-    @Override
-    public void unsetOrder() {
-      copyOnWrite();
-      shared.getSortCols().get(pos).unsetOrder();
-    }
-  }
-
-  private CopyOnWriteColList copyCols(List<FieldSchema> cols) {
-    if (colList == null) {
-      colList = new CopyOnWriteColList(cols.size());
-      for (int i = 0; i < cols.size(); i++) {
-        colList.secretAdd(new FieldSchemaWrapper(i, cols.get(i)));
-      }
-    }
-    return colList;
-  }
-
-  private class CopyOnWriteColList extends ArrayList<FieldSchema> {
-
-    CopyOnWriteColList(int size) {
-      super(size);
-    }
-
-    private void secretAdd(FieldSchemaWrapper col) {
-      super.add(col);
-    }
-
-    @Override
-    public boolean add(FieldSchema t) {
-      copyOnWrite();
-      return shared.getCols().add(t);
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      copyOnWrite();
-      return shared.getCols().remove(o);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends FieldSchema> c) {
-      copyOnWrite();
-      return shared.getCols().addAll(c);
-    }
-
-    @Override
-    public boolean addAll(int index, Collection<? extends FieldSchema> c) {
-      copyOnWrite();
-      return shared.getCols().addAll(c);
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      copyOnWrite();
-      return shared.getCols().removeAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      copyOnWrite();
-      return shared.getCols().retainAll(c);
-    }
-
-    @Override
-    public void clear() {
-      copyOnWrite();
-      shared.getCols().clear();
-    }
-
-    @Override
-    public FieldSchema set(int index, FieldSchema element) {
-      copyOnWrite();
-      return shared.getCols().set(index, element);
-    }
-
-    @Override
-    public void add(int index, FieldSchema element) {
-      copyOnWrite();
-      shared.getCols().add(index, element);
-    }
-
-    @Override
-    public FieldSchema remove(int index) {
-      copyOnWrite();
-      return shared.getCols().remove(index);
-    }
-  }
-
-  private class FieldSchemaWrapper extends FieldSchema {
-    final private int pos;
-
-    FieldSchemaWrapper(int pos, FieldSchema col) {
-      super(col);
-      this.pos = pos;
-    }
-
-    @Override
-    public void setName(String name) {
-      copyOnWrite();
-      shared.getCols().get(pos).setName(name);
-    }
-
-    @Override
-    public void unsetName() {
-      copyOnWrite();
-      shared.getCols().get(pos).unsetName();
-    }
-
-    @Override
-    public void setType(String type) {
-      copyOnWrite();
-      shared.getCols().get(pos).setType(type);
-    }
-
-    @Override
-    public void unsetType() {
-      copyOnWrite();
-      shared.getCols().get(pos).unsetType();
-    }
-
-    @Override
-    public void setComment(String comment) {
-      copyOnWrite();
-      shared.getCols().get(pos).setComment(comment);
-    }
-
-    @Override
-    public void unsetComment() {
-      copyOnWrite();
-      shared.getCols().get(pos).unsetComment();
-    }
-  }
-
-  private CopyOnWriteBucketList copyBucketCols(List<String> cols) {
-    if (bucketList == null) {
-      bucketList = new CopyOnWriteBucketList(cols);
-    }
-    return bucketList;
-  }
-
-  private class CopyOnWriteBucketList extends ArrayList<String> {
-
-    CopyOnWriteBucketList(Collection<String> c) {
-      super(c);
-    }
-
-    private void secretAdd(String col) {
-      super.add(col);
-    }
-
-    @Override
-    public boolean add(String t) {
-      copyOnWrite();
-      return shared.getBucketCols().add(t);
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      copyOnWrite();
-      return shared.getBucketCols().remove(o);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends String> c) {
-      copyOnWrite();
-      return shared.getBucketCols().addAll(c);
-    }
-
-    @Override
-    public boolean addAll(int index, Collection<? extends String> c) {
-      copyOnWrite();
-      return shared.getBucketCols().addAll(c);
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      copyOnWrite();
-      return shared.getBucketCols().removeAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      copyOnWrite();
-      return shared.getBucketCols().retainAll(c);
-    }
-
-    @Override
-    public void clear() {
-      copyOnWrite();
-      shared.getBucketCols().clear();
-    }
-
-    @Override
-    public String set(int index, String element) {
-      copyOnWrite();
-      return shared.getBucketCols().set(index, element);
-    }
-
-    @Override
-    public void add(int index, String element) {
-      copyOnWrite();
-      shared.getBucketCols().add(index, element);
-    }
-
-    @Override
-    public String remove(int index) {
-      copyOnWrite();
-      return shared.getBucketCols().remove(index);
-    }
-  }
-
 }
